package finalproject.view;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

import finalproject.controller.commands.Command;
/**
 * This class is charged of managing the string to allow easy internationalization
 * It uses the class Locale and ResourceBundle to load language file
 * These files associate a string key to another string, which is the text string
 *
 * The Locale class is used to load the file depending on the language locale.
 * For example Locale(en, US) will allow Resource bundle to seek for and load the i18n file corresponding to the english American translation
 * @author Nicolas Bighetti
 *
 */
public class StringManager{

	/**
	 * The StringManager instance
	 */
	private static StringManager instance = new StringManager();
	
	/**
	 * The colour used to colour key sentences (2 <= nb_Word <= 3
	 */
	public static final Color secondary = Color.GREEN;
	
	/**
	 * The colour used for normal sentences
	 */
	public static final Color normal = Color.BLACK;
	
	/**
	 * The colour used for keywords
	 */
	public static final Color keyWord = Color.RED;
	
	/**
	 * The colour used for special words that need coloration and can't be analyzed automatically
	 */
	public static final Color indication = Color.BLUE;
	/**
	 * The resourceBundle containing all the strings loaded
	 */
	private static ResourceBundle stringStack;
	
	/**
	 * List of all the coloured displayer
	 */
	private static List<ColouredDisplayer> displayers;
	
	/**
	 * List of all the keyword
	 */
	private List<String> keyWordList;
	
	/**
	 * List of all the secondary words
	 */
	private List<String> secondaryWordList;
	
	/**
	 * List of all the indication words
	 */
	private List<String> indicationList;
	
	
	/**
	 * That method allows to load the translation file corresponding to language and the country passsed as param
	 * If the corresponding file does not exist, an english translation is loaded by default
	 * @param language the language wanted
	 * @param country the country wanted
	 */
	
	private StringManager()
	{
		keyWordList = new ArrayList<String>();
		secondaryWordList = new ArrayList<String>();
		indicationList = new ArrayList<String>();
		loadIndicationList();
	}
	
	/**
	 * Load the indication list
	 * if you need words to take this color, add them here
	 */
	private void loadIndicationList() {
		indicationList.add("north");
		indicationList.add("south");
		indicationList.add("east");
		indicationList.add("west");
	}

	/**
	 * @return the StringManager instance
	 */
	public static StringManager getInstance()
	{
		return instance;
	}
	
	/**
	 * Load the language locale, allow i18n
	 * @param language the language
	 * @param country the country langage
	 */
	static public void loadLocale(String language, String country)
	{
		try
		{
			Locale currentLocale = new Locale(language, country);
			stringStack = ResourceBundle.getBundle("text", currentLocale);
			getInstance().getKeyWords();
			getInstance().getSecondaryList();
		}
		catch(Exception e)
		{
			//If we can't load a Locale translation, we load an english default one
			//----------------------------------------------------------------------
			e.printStackTrace();
			stringStack = ResourceBundle.getBundle("text");
		}
	}

	/**
	 * Select all the key words in the stringStack
	 * Keywords are one word long string from the data, they will be coloured differently
	 */
	private void getKeyWords() {
		String tmp;
		Iterator<String> i = stringStack.keySet().iterator();
		
		while(i.hasNext())
		{
			tmp = stringStack.getString(i.next()).trim().toLowerCase();
			if(isOneWordLong(tmp))
			{
				keyWordList.add(tmp);
			}
		}
		
		for (String string : Command.COMMANDS) {
			keyWordList.add(string);
		}
		
	}

	/**
	 * Tests if a string is one word long (only one space here)
	 * @param tmp the string to test
	 * @return true if one word long, false if not
	 */
	private boolean isOneWordLong(String tmp) {
		if(tmp.matches("^[a-zA-Z0-9_]+$"))
			return true;
		else return false;
	}

	/**
	 * Build the list of secondary words
	 * Secondarys words are translated sentences from the bundle that contains two or three words
	 */
	private void getSecondaryList() {
		
		String tmp;
		Iterator<String> i = stringStack.keySet().iterator();
		
		while(i.hasNext())
		{
			tmp = stringStack.getString(i.next()).trim().toLowerCase();
			if(numberOfSpace(tmp) == 1 || numberOfSpace(tmp) == 2)
			{
				secondaryWordList.add(tmp);
			}
		}
	}


	/**
	 * Add a displayer to the displayer list
	 * Next time a string is to be displayed, this displayer will also receive the data
	 * @param display the displayer to add
	 */
	public static void addDisplayer(ColouredDisplayer display)
	{
		if(displayers == null)
			displayers = new ArrayList<ColouredDisplayer>();
		
		displayers.add(display);
	}
	/**
	 * Instead of outputing a string, that method will return the key's corresponding string
	 * if the key is associated to no string, the method will return the key itself
	 * @param key the key to the string we want
	 * @return a string
	 */
	public static String getString(String key)
	{
		try
		{
			return stringStack.getString(key);
		}
		catch(Exception e)
		{
			return key;
		}
	}

	/**
	 * Allow to display string in the correct local using identification key
	 * @param key the key to the phrase you wanna display
	 */
	public static void outPut(String key) {
			getInstance().colorText(getString(key).trim());
	}
	/**
	 * Allow to display misc. string
	 * @param string the string to display
	 */
	public static void outPutText(String string) {
			getInstance().colorText(string.trim());
	}
	
	/**
	 * this method takes a string in input, and colour it depending on the words that are to highligthed from the lists
	 * @param string the string to colour
	 */
	private void colorText(String string)
	{

		//We split the string into smaller part for each space
		//------------------------------------------------------
		
		String words[] = string.split(" ");
		//Contains the different parts of the string, and the associated colour
		//----------------------------------------------------------------------
		Map<String, Color> sentencesBuffer = new LinkedHashMap<String, Color>();
		String buffer = "";
		String keyWordTest ="";
		
		
		for (String str : words) {
			
			//If the last words analyzed + the next word are in the secondary list or the indication list, we color them as secondary
			//-------------------------------------------------------------------------------------------------------------------
			if(secondaryWordList.contains((keyWordTest+ " " + str).trim().toLowerCase()))
			{
				sentencesBuffer.put((keyWordTest+ " " + str).trim() +" ", secondary);
				keyWordTest = "";
				continue;
			}
			else if (indicationList.contains(keyWordTest+ " " + str))
			{
				sentencesBuffer.put((keyWordTest+ " " + str).trim() +" ", indication);
				keyWordTest = "";
				continue;
			}
			//Else if only the current word is important, we colour it as a keyword
			//----------------------------------------------------------------------
			else
				sentencesBuffer.put(keyWordTest.trim()+" ", keyWord);
				
				
			//If the current word is contained in the keyword list
			//-----------------------------------------------------
			if(keyWordList.contains(str.trim().toLowerCase()))
			{
				if(!buffer.equals(""))
				{
					sentencesBuffer.put(buffer.trim()+" ", normal);
					buffer = "";
				}
				
				keyWordTest = str.trim();
				continue;
			}
			
			//If the current word is an indication word
			//-----------------------------------------------
			if(indicationList.contains(str.trim().toLowerCase()))
			{
				if(!buffer.equals(""))
				{
					sentencesBuffer.put(buffer.trim() +" ", normal);
					buffer = "";
				}
				
				sentencesBuffer.put(str.trim() +" ", indication);
				continue;
			}
			
			buffer+=str+" ";
			
			//If the concatenation of the newest word and the buffer of previous words is contained by any of thhe lists below
			//------------------------------------------------------------------------------------------------------------------
			if(indicationList.contains(buffer.trim().toLowerCase()))
			{
				sentencesBuffer.put(buffer.trim() +" ", indication);
				buffer = "";
			}
			
			if(secondaryWordList.contains(buffer.trim().toLowerCase()))
			{
				sentencesBuffer.put(buffer.trim() +" ", secondary);
				buffer = "";
			}
			
			//We clear the buffer to allow secondary words to be recognised, the buffer will get the normal colour
			//------------------------------------------------------------------------------------------------------
			sentencesBuffer.put(buffer.trim() + " ", normal);
			buffer = "";
		}
		
		//If there is still a word in keyWordTest, we addd it as a keyword
		//-----------------------------------------------------------------
		if(keyWordList.contains(keyWordTest.trim().toLowerCase()))
			sentencesBuffer.put(keyWordTest.trim()+" ", keyWord);
		
		//We parse the map colour, and we send the different part of the string to the colouredDisplayer
		//---------------------------------------------------------------------------------------------
		Iterator<String> i = sentencesBuffer.keySet().iterator();
		String tmp;
		while(i.hasNext())
		{
			tmp = i.next();
			sendToDisplayer(sentencesBuffer.get(tmp), tmp);
		}
		
		sendToDisplayer(normal, buffer+"\n");
		
	}

	/**
	 * Get the number of space contained in a givven string
	 * @param s the string s
	 * @return the number of space in the string
	 */
	private int numberOfSpace(String s)
	{
		int count = 0;
		for(int i = 0; i < s.length(); i++)
			if(s.charAt(i) == ' ')
				count ++;
		return count;
				
	}
	
	/**
	 * Send a string to all the coloured displayer for display
	 * @param c the color the text will take
	 * @param s the text to be displayed
	 */
	public void sendToDisplayer(Color c, String s)
	{
		for (ColouredDisplayer colouredDisplayer : displayers) {
			colouredDisplayer.displayString(c, s);
		}
	}
}